﻿
namespace N_dimenslArr
{
  using System;
  using System.Collections.Generic;
  using System.ComponentModel;
  using System.Data;
  using System.Diagnostics;
  using System.Drawing;
  using System.Linq;
  using System.Text;
  using System.Threading;
  using System.Windows.Forms;
  using MapleRock.P2PEmulator.Core;
  using MapleRock.P2PEmulator.Core.Events;
  using Tao.FreeGlut;
  using Tao.OpenGl;
  using Tao.Platform.Windows;

  public partial class MainForm : Form
  {
    private const int SquareSize = 50;

    private XmlReport report = new XmlReport();
    private GeographyScene geoScene = new GeographyScene();
    private Dictionary<BaseEvent, System.Windows.Forms.Timer> timers = new Dictionary<BaseEvent, System.Windows.Forms.Timer>();
    //private EventsCursor eventsCursor = new EventsCursor(@"e:\N-dimenslArr\n-dimensional-array\bin\Debug\out.bin");
    private EventsCursor eventsCursor;// = new EventsCursor("out.bin");
    private System.Windows.Forms.Timer playTimer = new System.Windows.Forms.Timer();
    private string networkEventsFilePath = new string('0', 1);
    private string networkParamsFilePath = new string('0', 1);
    private int[] lastMousePosition;
    private int[] pressMousePosition;

    public MainForm()
    {
      InitializeComponent();
      AnT.InitializeContexts();
    }

    private void Form1_Load(object sender, EventArgs e)
    {
      this.lastMousePosition = new int[2];
      this.pressMousePosition = new int[2];

     
      //this.networkParamsFilePath = @"e:\N-dimenslArr\n-dimensional-array\bin\Debug\out.xml";
      //this.networkEventsFilePath = @"e:\N-dimenslArr\n-dimensional-array\bin\Debug\out.bin";


      this.geoScene = new GeographyScene(AnT.Width, AnT.Height, SquareSize);
      this.geoScene.InitGraphicsSystem();
      this.geoScene.Render();
      AnT.Invalidate();
    }

    private void AboutToolStripMenuItem_Click(object sender, EventArgs e)
    {
      

    }

    private void AdjacencyMatrixFill(int[,] adjacencyMatrix, int citiesCount, string citiesAdjacency)
    {
      Debug.Assert(adjacencyMatrix.GetLength(0) == citiesCount, "adjacencyMatrix.GetLength(0) == citiesCount");
      Debug.Assert(adjacencyMatrix.GetLength(1) == citiesCount, "adjacencyMatrix.GetLength(1) == citiesCount");

      var adjacencyParts = citiesAdjacency.Split(' '); 

      for (var i = 0; i < citiesCount; ++ i)
      {
        for (var j = 0; j < citiesCount; ++j)
        {
          var entry = adjacencyParts[(i * citiesCount) + j];

          Debug.Assert (("0" == entry) || ("1" == entry), "(\"0\" == entry) || (\"1\" == entry)");

          if ("1" == entry)
          {
            adjacencyMatrix[i,j] = 1;
          }
          else if ("0" == entry)
          {
            adjacencyMatrix[i,j] = 0;
          }
          else
          {
            throw new FormatException("Unexpected adjacency table entry");
          }
        }
      }
      
    }

    private void OpenFile_ToolStripMenuItem2_Click(object sender, EventArgs e)
    {
      var openDlg = new OpenFileDialog();
      openDlg.Filter = "Output Meta (out*.xml)|out*.xml|All Files (*.*)|*.*";
      if (DialogResult.OK != openDlg.ShowDialog(this))
      {
        this.Close();
        return;
      }

      this.networkParamsFilePath = openDlg.FileName;
      this.report = XmlReport.Load(networkParamsFilePath);

      openDlg = new OpenFileDialog();
      openDlg.Filter = "Output Binary (out*.bin)|out*.bin|All Files (*.*)|*.*";
      if (DialogResult.OK != openDlg.ShowDialog(this))
      {
        this.Close();
        return;
      }

      this.networkEventsFilePath = openDlg.FileName;
      this.eventsCursor = new EventsCursor(this.networkEventsFilePath);

      double longitude = this.report.InputData.Geography[0].AreaLongitude;
      double latitude = this.report.InputData.Geography[0].AreaLatitude;
      string citiesAdjacencyString = this.report.CitiesAdjacency;

      this.geoScene = new GeographyScene(latitude, longitude, AnT.Width, AnT.Height, SquareSize);

      this.geoScene.InitGraphicsSystem();

      foreach (XmlCity city in this.report.Cities)
      {
        this.geoScene.AddCity(City.FromXmlCity(city));
      }

      string citiesAdjacency = citiesAdjacencyString.Remove(0, 2);
      int citiesCount = int.Parse(citiesAdjacencyString.Remove(1));
      int[,] adjacencyMatrix = new int[citiesCount, citiesCount];

      this.AdjacencyMatrixFill(adjacencyMatrix, citiesCount, citiesAdjacency);

      for (int i = 1; i < citiesCount; ++i)
      {
        for (int j = 1; j < citiesCount; ++j)
        {
          if (adjacencyMatrix[i, j] == 1)
          {
            var iCity = this.report.Cities[i - 1];
            var jCity = this.report.Cities[j - 1];

            double[] from = { iCity.Latitude, iCity.Longitude };
            double[] to = { jCity.Latitude, jCity.Longitude };
            GeoLink link = new GeoLink(from, to);
            link.Status = false;
            link.FromId = (uint)i;
            link.ToId = (uint)j;
            this.geoScene.AddLink(link);
          }
        }
      }

      PeerScene scene = new PeerScene();
      foreach (XmlPeer peer in this.report.InitialState)
      {
        scene.AddNode(Node.FromXmlNode(peer));
        double[] from = { this.report.Cities[(int)peer.CityId - 1].Latitude, this.report.Cities[(int)peer.CityId - 1].Longitude };
        double[] to = Node.FromXmlNode(peer).PositionNumeric;
        Link link = new Link(from, to);
        link.Status = false;
        link.FromId = peer.Id;
        link.ToId = peer.CityId;
        scene.AddLink(link);
      }

      scene.AddPacket(new Packet());

      this.geoScene.SetPeerScene(scene);

      this.geoScene.Render();
      this.label17.Visible = true;
      this.label13.Visible = true;
      this.label16.Visible = true;
      this.label12.Visible = true;
      this.label22.Visible = true;
      this.label23.Visible = true;
      this.label24.Visible = true;
      this.label26.Visible = true;
      this.label32.Visible = true;
      this.label30.Visible = true;
      this.label31.Visible = true;
      this.playButton.Enabled = true;
      this.stopButton.Enabled = true;
      this.pauseButton.Enabled = true;
      this.nextstepButton.Enabled = true;
      this.fastPlayButton.Enabled = true;
      this.centerView.Enabled = true;
      this.trackBar1.Enabled = true;
      this.Update();

      AnT.Invalidate();
    }

    private void AnT_MouseDown(object sender, MouseEventArgs e)
    {
      if ((Control.MouseButtons == MouseButtons.Right) || (Control.MouseButtons == MouseButtons.Left))
      {
        if (Control.MouseButtons == MouseButtons.Left)
        {
          int deltaX = e.X - this.lastMousePosition[0];
          int deltaY = e.Y - this.lastMousePosition[1];

          {
            this.geoScene.Move(deltaX, deltaY);
          }

          this.pressMousePosition[0] = e.X;
          this.pressMousePosition[1] = e.Y;

          this.geoScene.MousePressX = e.X;
          this.geoScene.MousePressY = e.Y;

          this.geoScene.Zooming = true;
        }

        this.lastMousePosition[0] = e.X;
        this.lastMousePosition[1] = e.Y;
      }
    }

    private void AnT_MouseMove(object sender, MouseEventArgs e)
    {
      int deltaX = e.X - this.lastMousePosition[0];
      int deltaY = e.Y - this.lastMousePosition[1];
    
      if (Control.MouseButtons == MouseButtons.Right)
      {
        this.geoScene.Move(deltaX, deltaY);
      }

      if (Control.MouseButtons == MouseButtons.Left)
      {
        if (deltaY < 0)
        {
          this.geoScene.SetZoom(Math.Sqrt(Math.Pow(deltaX, 2) + Math.Pow(deltaY, 2)) * 0.1);
        }
        else
        {
          this.geoScene.SetZoom(-Math.Sqrt(Math.Pow(deltaX, 2) + Math.Pow(deltaY, 2)) * 0.1);
        }
        if ((this.geoScene.Zoom > 1.0) && (this.geoScene.Zoom < 2.0))
        {
          this.trackBar1.Value = (int)((this.geoScene.Zoom) * 50.0);
        }
      }

      this.lastMousePosition[0] = e.X;
      this.lastMousePosition[1] = e.Y;
      AnT.Invalidate();
    }

    private void CreateModel_ToolStripMenuItem_Click(object sender, EventArgs e)
    {
      this.geoVisualizationTabControl.SelectTab(1);
    }

    private void OpenFileDialog1_FileOk(object sender, CancelEventArgs e)
    {
      this.geoVisualizationTabControl.SelectTab(0);
    }

    private void PlayButton_Click(object sender, EventArgs e)
    {
      playTimer.Interval = 2000;
      playTimer.Tick += this.playTimerEventHandler;
      playTimer.Start();
      this.playButton.Visible = false;
      this.pauseButton.Visible = true;
      this.pauseButton.Update();
      this.playButton.Update();
    }

    private void PauseButton_Click(object sender, EventArgs e)
    {
      this.playTimer.Stop();
      this.playButton.Visible = true;
      this.pauseButton.Visible = false;
      this.pauseButton.Update();
      this.playButton.Update();
    }

    private void stopButton_Click(object sender, EventArgs e)
    {
      this.playTimer.Stop();
      this.playButton.Visible = true;
      this.pauseButton.Visible = false;
      this.pauseButton.Update();
      this.playButton.Update();

      foreach (KeyValuePair<BaseEvent, System.Windows.Forms.Timer> pair in this.timers)
      {
        ((System.Windows.Forms.Timer)pair.Value).Stop();
        ((System.Windows.Forms.Timer)pair.Value).Dispose();

        TranslationEvent transEvent = ((TranslationEvent)pair.Key);

        foreach (Link link in this.geoScene.peerScene.links)
        {
          if ((link.FromId == transEvent.FromId) && (link.ToId == transEvent.ToId))
          {
            link.Status = false;
          }
        }

        foreach (GeoLink link in this.geoScene.links)
        {
          if ((link.FromId == transEvent.FromId) && (link.ToId == transEvent.ToId))
          {
            link.Status = false;
          }
        }
        this.geoScene.Render();
        AnT.Invalidate();
      }

      this.timers.Clear();
      this.traceTextBox.Clear();

      this.eventsCursor.Close();
      this.eventsCursor = new EventsCursor(this.networkEventsFilePath);
    }

    private void Exit_ToolStripMenuItem_Click(object sender, EventArgs e)
    {
      Application.Exit();
    }

    private void NextStepButton_Click(object sender, EventArgs e)
    {
      if (!this.eventsCursor.Next())
      {
        this.playTimer.Stop();
        this.playButton.Visible = true;
        this.pauseButton.Visible = false;
        this.pauseButton.Update();
        this.playButton.Update();
        return; 
      }

      this.traceTextBox.Text += "\r\r\n" + this.eventsCursor.GetCurrentEvent().ToString();
      if (this.eventsCursor.GetCurrentEvent().Type == EventType.TranslationEvent)
      {
        TranslationEvent transEvent = (TranslationEvent)this.eventsCursor.GetCurrentEvent();
        if (transEvent.Status == TranslationStatus.Begin)
        {
          System.Windows.Forms.Timer timer = new System.Windows.Forms.Timer();
          timer.Tag = transEvent;
          this.timers.Add((this.eventsCursor.GetCurrentEvent()), timer);
          this.timers[transEvent].Tick += this.TranslationTickEventHandler;
          this.timers[transEvent].Interval = 500;
          this.timers[transEvent].Start();
        }
        else
        {
          if (transEvent.Status == TranslationStatus.Success)
          {
            foreach (BaseEvent key in this.timers.Keys)
            {
              if (!(key is TranslationEvent))
              {
                continue;
              }

              TranslationEvent baseEvent = (TranslationEvent)key;
              bool isMatching = (baseEvent.Status == TranslationStatus.Begin);
              isMatching &= (baseEvent.FromId == transEvent.FromId);
              isMatching &= (baseEvent.ToId == transEvent.ToId);
              if (isMatching)
              {
                this.timers[key].Stop();

                foreach (Link link in this.geoScene.peerScene.links)
                {
                  if ((link.FromId == transEvent.FromId) && (link.ToId == transEvent.ToId))
                  {
                    link.Status = false;
                  }
                }

                foreach (GeoLink link in this.geoScene.links)
                {
                  if ((link.FromId == transEvent.FromId) && (link.ToId == transEvent.ToId))
                  {
                    link.Status = false;
                  }
                }

                this.timers.Remove(key);
                break;
              }
            }
          }
        }
      }
      this.geoScene.Render();
      AnT.Invalidate();
    }
    
    private void playTimerEventHandler(object sender, EventArgs e)
    {
      this.NextStepButton_Click(sender, e);
    }

    private void TranslationTickEventHandler(object sender, EventArgs e)
    {
      System.Windows.Forms.Timer timer = new System.Windows.Forms.Timer();
      timer = (System.Windows.Forms.Timer)sender;
      TranslationEvent transEvent = (TranslationEvent)timer.Tag;
      this.LinkStatusSwitcher(transEvent);
      /*if (transEvent.FromType == TranslationAgentType.Peer)
      {
          this.LinkStatusSwitcher(transEvent);
      }
      else 
      {*/
      if ((transEvent.FromType == TranslationAgentType.Router) && ((transEvent.ToType == TranslationAgentType.Router)))
      {
        foreach (GeoLink link in this.geoScene.links)
        {
          if ((link.FromId == transEvent.FromId) && (link.ToId == transEvent.ToId))
          {
            if (link.Status)
            {
              link.Status = false;
            }
            else
            {
              link.Status = true;
            }
          }
        }
      }
      /* else
       {
           this.LinkStatusSwitcher(transEvent);
       }
   }*/

      this.geoScene.Render();
      AnT.Invalidate();
    }

    private void LinkStatusSwitcher(TranslationEvent transEvent)
    {
      foreach (Link link in this.geoScene.peerScene.links)
      {
        if ((link.FromId == transEvent.FromId) && (link.ToId == transEvent.ToId))
        {
          if (link.Status)
          {
            link.Status = false;
          }
          else
          {
            link.Status = true;
          }
        }
      }
    }

    private void AnT_MouseUp(object sender, MouseEventArgs e)
    {
      this.geoScene.Zooming = false;
    }

    private void trackBar1_Scroll(object sender, EventArgs e)
    {
      double zoom = 1 + (trackBar1.Value / 50.0);
      this.geoScene.Zoom = zoom;
      this.geoScene.Render();
      AnT.Invalidate();
    }

    private void button1_Click(object sender, EventArgs e)
    { 
      this.geoScene.Zoom = 1;
      this.geoScene.Shift[0] = 0;
      this.geoScene.Shift[1] = 0;
      this.trackBar1.Value = trackBar1.Minimum;
      this.geoScene.Render();
      AnT.Invalidate();
    }

    private void button1_Click_1(object sender, EventArgs e)
    {
      if (playTimer.Interval > 1000)
      {
        playTimer.Interval /= 2;
      }
    }    

  }
}
